package com.fucking.great.context.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import com.fucking.great.context.TxnContext;
import com.fucking.great.context.constant.HttpConstant;
import com.fucking.great.context.exception.TxnRuntimeException;
import com.fucking.great.context.config.*;
import com.fucking.great.context.engine.*;
import com.fucking.great.context.manager.PlugManager;
import com.fucking.great.context.plun.*;
import com.fucking.great.context.util.SingleUtil;

import java.util.*;

/**
 * 单例,自己控制一下单例模式吧。
 * 如在servlert 中 init()
 * 这里默认匹配   /类名/方法名.
 */
public abstract class HandlerTemplate implements GreatHandler {
    // 执行
    static{
        // 获得配置内容.
        TxnConfiger txnConfinger = SingleUtil.getBean(TxnConfiger.class);
        String[] allSystemName = txnConfinger.getAllSystemName();
        //
        int length = allSystemName.length;
        SystemConfigBean[] allSystemConfigBean = new SystemConfigBean[length];
        for (int i = 0; i < length; i++) {
            allSystemConfigBean[i] = txnConfinger.getSystemConfigBean( allSystemName[i]);
        }

        //
        List<AppRunner> allImpBean = SingleUtil.getAllImpBean(AppRunner.class);
        allImpBean.forEach(x -> x.run(allSystemConfigBean) );
    }


    protected HandlerTemplate(){}

    /**
     * 为什么要说hello，
     * 1. 统一开发规范.
     * 2. 以前调用微服务，涉及事务该怎么处理??
     * 比如转账发起接口请求后，业务失败了，我需要手动调用退款的服务.
     *
     * @param text
     * @return
     */
    @Override
    public Object doService(TxnContext text) {
        Log log = text.getLogger();

        TxnRuntimeException runtimeException = null;
        //
        Engine scriptEnginer = getEngine();
        // 获得配置内容.
        TxnConfiger txnConfinger = SingleUtil.getBean(TxnConfiger.class);
        String path = null;
        String systemName= null;
        PathConfigBean pathConfigBean= null;
        SystemConfigBean systemConfigBean = null;
        try {
            // 获得配置
            path = text.getPath();
            systemName = text.getSystemName();
            // 获得配置.
            pathConfigBean = txnConfinger.getPathConfigBean(path);
            systemConfigBean = txnConfinger.getSystemConfigBean(systemName);
        } finally {
            log.info("path=[{}]systemName=[{}]pathConfigBean=[\n{}\n]systemConfigBean=[\n{}\n]", path,systemName,pathConfigBean,systemConfigBean);
        }
        // 获得需要使用的组件工厂.
        List<Plug> PlugList = null;
        Set<String> importAllSet = null;
        Object result = null;
        // 获得插件管理者。
        PlugManager plugManager = text.getPlugManager();
        try {
            // init   插件管理者
            PlugList = plugManager.initPlug(systemConfigBean,pathConfigBean, txnConfinger);
            // 获得所有的导包名:
            importAllSet = plugManager.getImportAllSet();
            String[] importPackage = pathConfigBean.getImportPackage();
            CollectionUtil.addAll(importAllSet,importPackage);

            Map<String, Object> plunAllMap = null;
            // begin
           plunAllMap = plugManager.beginUser(PlugList);


            // 清空历史异常
            text.setErrorMessage(null);
            text.setErrorCode(null);

            // do
            // 获得执行脚本.
            result = execPathScript( pathConfigBean, importAllSet, scriptEnginer, plunAllMap);

        } catch (TxnRuntimeException e) {
            runtimeException = e;
        } catch (Throwable e) {
            TxnRuntimeException.throwException("500", e);
            log.error(e, "系统异常码请核查程序");
        }

        // 判断异常，执行回滚。回滚但是不关闭连接
        if (runtimeException != null) {
            text.setErrorCode(runtimeException.getErrorCode());
            String message = runtimeException.getMessage();
            if (StrUtil.isBlank(message)) {
                Throwable throwable = runtimeException.getThrowable();
                if (throwable != null) {
                    message = throwable.toString();
                }else{
                    message = "系统异常,请核查程序";
                }
            }
            text.setErrorMessage(message);
        }

        // 处理结果集，返回供前端展示.
        result = handleResult(text,systemConfigBean, runtimeException, importAllSet, result, scriptEnginer);

        // comit or rollback
        try{
            if (text.hasException()) {
                // 报错,每个组件都执行回滚操作。
                plugManager.quietRollback(PlugList);
            }else{
                // 执行代码。
                // 没报错,每个组件都执行提交操作。
                plugManager.commit(PlugList);
            }
        }finally {
            //  TxnContext 结束释放。
            text.endContext();
        }
        //
        return result;
    }



    protected Object handleResult(TxnContext text,SystemConfigBean systemConfigBean, TxnRuntimeException runtimeException,  Set<String> importAllSet, Object result, Engine scriptEnginer) {
        String resultScript = systemConfigBean.getResultScript();
        if (StrUtil.isNotBlank(resultScript)) {
            // 有全局处理内容
            Map<String, Object> plunMap = new HashMap<>();
            plunMap.put("exception", runtimeException);
            plunMap.put("result", result);
            //
            String systemName = systemConfigBean.getSystemName();
            result = scriptEnginer.engine(systemName, importAllSet, resultScript, plunMap);
        }  else {
            // 默认方式处理
            String contentType = text.getResponseHeader().getStr(HttpConstant.CONTENT_TYPE, "");
            if(contentType.contains(HttpConstant.CONTENT_TYPE_JSON)){
                result = text.showResult(result);
            }else{
                // 其他的原样返回。
            }
        }
        return result;
    }

    protected Object execPathScript(PathConfigBean pathConfigBean, Set<String> importAllSet, Engine scriptEnginer, Map<String, Object> plunAllMap ) {
        Object result;
        String path = pathConfigBean.getPath();
        String serviceScript = pathConfigBean.getServiceScript();
        // 内容不能为空。
        if (StrUtil.isEmpty(serviceScript))
            TxnRuntimeException.throwException("404", "SYSTEM Exception ::  No corresponding service was found");
        result = scriptEnginer.engine(path, importAllSet, serviceScript, plunAllMap);
        return result;
    }



    /**
     * 获得执行脚本引擎
     * @return
     */
    protected Engine getEngine(){
        return SingleUtil.getBean(Engine.class);
    }

    /**
     */
    @Override
    public void destroy(){
        //
        TxnConfiger txnConfiger = SingleUtil.getBean(TxnConfiger.class);
        txnConfiger.getAllPlugFactory().forEach(x -> x.destroy());
        //
        List<AppRunner> allImpBean = SingleUtil.getAllImpBean(AppRunner.class);
        allImpBean.forEach(x -> x.destroy() );
    }
}
